/*
 * pwm.h
 *
 * PWM0/PWM1 
 *
 * Copyright (C) 2022 Microwell, Inc.
 * Subject to the GNU Public License, version 2.
 *
 * Author: guoming<guoming@microwell.net>
 */
#ifndef _PWM_H_
#define _PWM_H_

#include "core.h"

/**
 * @brief duty reload
 * MAX_VAL is timer max value
 * Duty cycle ranges from 0 to 100
 */
#define TIMER0_DUTY_VAL(FREQ, DUTY)          (TIMER0_MAX_VAL - 1 - (100 - DUTY) * (SYS_SCLK_FREQ / CONFIG_TIMER0_TCLKDIV / FREQ) / 100)
#define TIMER1_DUTY_VAL(FREQ, DUTY)          (TIMER1_MAX_VAL - 1 - (100 - DUTY) * (SYS_SCLK_FREQ / CONFIG_TIMER1_TCLKDIV / FREQ) / 100)

/**
 * @brief please refer to TCON1_REG
 * PWM0 = TPS0; PWM1 = TPS1;
 * LEVEL polarity: 1, high active; 0, low active
 */
#define PWM0_POLARITY_SET(LEVEL)             MODIFY_REG(TCON1, TPS0, (LEVEL << 0))
#define PWM1_POLARITY_SET(LEVEL)             MODIFY_REG(TCON1, TPS1, (LEVEL << 0))

/**
 * @brief for auto 8 timer mode
 * 
 */
#define PWM0_DUTY_SET_A_FREQ(DUTY,FREQ)      WRITE_REG(TPDL0, TIMER0_DUTY_VAL(FREQ, DUTY))
#define PWM1_DUTY_SET_A_FREQ(DUTY,FREQ)      WRITE_REG(TPDL1, TIMER1_DUTY_VAL(FREQ, DUTY))
#define PWM0_DUTY_SET(DUTY)                  WRITE_REG(TPDL0, TIMER0_DUTY_VAL(CONFIG_TIMER0_FREQ, DUTY))
#define PWM1_DUTY_SET(DUTY)                  WRITE_REG(TPDL1, TIMER1_DUTY_VAL(CONFIG_TIMER1_FREQ, DUTY))
#define PWM0_DUTY_READ()                     READ_REG(TPDL0)
#define PWM1_DUTY_READ()                     READ_REG(TPDL1)
#define PWM0_FREQ_DUTY_SET(FREQ, DUTY)       WRITE_REG(TPDL0, TIMER0_DUTY_VAL(FREQ, DUTY))
#define PWM1_FREQ_DUTY_SET(FREQ, DUTY)       WRITE_REG(TPDL1, TIMER1_DUTY_VAL(FREQ, DUTY))

#define PWM0_FREQ_SET(FREQ)                  WRITE_REG(TH0, TIMER0_FREQ_VAL(FREQ))
#define PWM1_FREQ_SET(FREQ)                  WRITE_REG(TH1, TIMER1_FREQ_VAL(FREQ))

#define PWM0_MODE_ENABLE(EN)                 MODIFY_REG(TCON, TPE0_BIT, (EN << 1))
#define PWM1_MODE_ENABLE(EN)                 MODIFY_REG(TCON, TPE1_BIT, (EN << 5))

#if(PWM_CHANNEL_MODE)
void pwm_init(void);
void pwm_set_polarity(uint8_t pwm, uint8_t polarity);
void pwm_set_duty(uint8_t pwm, uint16_t duty);
void pwm_set_duty_according_freq(uint8_t pwm, uint16_t duty, uint32_t freq);
void pwm_exit(void);
void pwm_io_enable(uint8_t pwm);
void pwm_io_disable(uint8_t pwm);
void pwm_io_set_freq(uint8_t pwm, uint32_t freq);
uint16_t pwm_io_get_max_duty(uint8_t pwm);
#else
#define pwm_init()
#define pwm_set_polarity(pwm, polarity)                 (pwm, polarity)
#define pwm_set_duty(pwm, duty)                         (pwm, duty)
#define pwm_set_duty_according_freq(pwm, duty, freq)    (pwm, duty, freq)
#define pwm_exit()
#define pwm_io_enable(pwm)                              (pwm)
#define pwm_io_disable(pwm)                             (pwm)
#define pwm_io_set_freq(pwm, freq)                      (pwm, freq)
#define pwm_io_get_max_duty(pwm)                        (pwm)
#endif

#endif
